/*
 * @(#)DynamicConfigTester.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.test;

import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockFilterConfig;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.nhncorp.lucy.common.container.SpringBeanFactory;
import com.nhncorp.lucy.common.util.ResourceLoader;
import com.nhncorp.lucy.common.util.XMLDOMUtil;
import com.nhncorp.usf.core.UsfDispatcher;
import com.nhncorp.usf.core.config.AttributeInfo;
import com.nhncorp.usf.core.config.ConnectorInfo;
import com.nhncorp.usf.core.config.ConnectorInfos;
import com.nhncorp.usf.core.service.UsfServiceExecutorTester;
import com.nhncorp.usf.core.servlet.ConfigurationLoaderListener;
import com.nhncorp.usf.core.servlet.ServletContextHolder;
import com.nhncorp.usf.core.servlet.UsfFilter;

/**
 * @author Web Platform Development Team
 */
public class DynamicConfigTester {
	Log log = LogFactory.getLog(DynamicConfigTester.class);
	
	private static final String DEFAULT_WEBXML_LOCATION = "WEB-INF/web.xml";
	private String webXmlLocation;
	private Document webXmlDom;
	private UsfFilter filter = new UsfFilter();
	
	public DynamicConfigTester() {
		this(DEFAULT_WEBXML_LOCATION);
	}
	
	public DynamicConfigTester(String webXmlLocation) {
		this.webXmlLocation = webXmlLocation;

		try {
			loadWebXmlDom();
			initConfigurationLoaderListener();
			initAttributeInfo();
			initFilter();
			initSpringFactory();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * SpringFactory 를 사용하는 경우 Factory init <br/>
	 * 물론 SpringFactory 를 사용하지 않기로 했지만 나는 쓰는게 편해서;;
	 * */
	private void initSpringFactory() {
		for (Entry<String, ConnectorInfo> entry : ConnectorInfos.getInstance().getEntrys()) {
			ConnectorInfo connectorInfo = entry.getValue();
			
			if ("lucy://localhost".equalsIgnoreCase(connectorInfo.getAddress())) {
				ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext*.xml");
				SpringBeanFactory.init(applicationContext);
			}
		}
	}

	/**
	 * request, response 를 받아서 USF 를 실행한다.
	 * 
	 * @param request {@link HttpServletRequest}
	 * @param response {@link HttpServletResponse}
	 * @return {@link ExecuteInfo} 실행 결과
	 * @throws Exception exception
	 * */
	public ExecuteInfo execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Filter 로 실행
		MockFilterChain chain = new MockFilterChain();
		filter.doFilter(request, response, chain);
		
		// 결과 가져오기
		UsfDispatcher dispatcher = UsfDispatcher.getInstance();
		MockResultGenerator generator = (MockResultGenerator) dispatcher.getResultGenerator();
		UsfServiceExecutorTester executor = (UsfServiceExecutorTester) dispatcher.getServiceExecutor();
		
		// 출력할 결과로 꾸미기
        ExecuteInfo executeInfo = executor.getExecuteInfo();
        executeInfo.setResultPageInfo(generator.getResultPageInfo());
        Map<String, Object> dataModel = generator.getDataModel();
        executeInfo.setDataModel(dataModel);
        
		return executeInfo;
	}

	/**
	 * Filter 를 로딩한다.
	 * 
	 * @throws ServletException servletException
	 * */
	@SuppressWarnings("deprecation")
	private void initFilter() throws ServletException {
		MockFilterConfig filterConfig = new MockFilterConfig(ServletContextHolder.get());
		Iterator<Node> it = XMLDOMUtil.getNodeIterator(webXmlDom.getDocumentElement(), "/web-app/filter");
		
		while (it.hasNext()) {
			Node node = it.next();
			String filterName = XMLDOMUtil.getValue(node, "filter-name");
			
			if (!"usf".equals(filterName)) {
				continue;
			}
			
			Iterator<Node> initParams = XMLDOMUtil.getNodeIterator(node, "init-param");
			
			while (initParams.hasNext()) {
				Node initParam = initParams.next();
				String paramName = XMLDOMUtil.getValue(initParam, "param-name");
				String paramValue = XMLDOMUtil.getValue(initParam, "param-value");
				filterConfig.addInitParameter(paramName, paramValue);
			}
		}
		
		filter.init(filterConfig);
	}

	/**
	 * web.xml 을 로딩한다.
	 * 
	 * @throws Exception exception
	 * */
	private void loadWebXmlDom() throws Exception {
		ResourceLoader loader = new ResourceLoader();
		
    	InputStream is = loader.getResourceAsStream(webXmlLocation);
		webXmlDom = XMLDOMUtil.loading(is, false);
	}

	/**
	 * ServletContext 를 초기화 한다.
	 * */
	@SuppressWarnings("deprecation")
	private void initConfigurationLoaderListener() {
		// XworkInterceptorMapping.clear();
		ConnectorInfos.getInstance().clear();
		
		ConfigurationLoaderListener listener = new ConfigurationLoaderListener();
		MockServletContextExt context = new MockServletContextExt();
		
		Iterator<Node> it = XMLDOMUtil.getNodeIterator(webXmlDom.getDocumentElement(), "/web-app/context-param");
		
		while (it.hasNext()) {
			Node node = it.next();
			String paramName = XMLDOMUtil.getValue(node, "param-name");
			String paramValue = XMLDOMUtil.getValue(node, "param-value");
			context.addInitParameter(paramName, paramValue);
		}
		
		ServletContextEvent event = new ServletContextEvent(context);
		listener.contextInitialized(event);
	}
	
	/**
	 * ServiceExecutor 와 ResultGenerator 를 Mock 으로 설정한다.
	 * */
	private void initAttributeInfo() {
		AttributeInfo.getInstance().addAttribute(AttributeInfo.ATTRIBUTE_NAME.serviceExecutor.name(), "com.nhncorp.usf.core.service.UsfServiceExecutorTester");
		AttributeInfo.getInstance().addAttribute(AttributeInfo.ATTRIBUTE_NAME.resultGenerator.name(), "com.nhncorp.usf.test.MockResultGenerator");
	}
}
